package crypto.attack.differential.higher.data;

import java.io.FileOutputStream;
import java.io.PrintStream;

import crypto.util.ExtendedFunctionType;

public class Generate {
	private ExtendedFunctionType fun = null;
	private PrintStream out = null;
	private int inputLength = 0;
	private int outputLength = 0;
	private int d = 0;
	private int maxIn = 0;
	private int maxOut = 0;
	private int[] tmp = new int[32];

	public Generate(ExtendedFunctionType fun, int d, PrintStream out) {
		this.fun = fun;
		this.out = out;
		this.d = d;
		inputLength = fun.getInputLength();
		outputLength = fun.getOutputLength();
		maxIn = (1 << inputLength) - 1;
		maxOut = (1 << outputLength) - 1;

		splitTest("101011 111110 111111");
		splitTest("101010 111110 111111");
		splitTest("010101 111110 111111");
		splitTest("010100 111110 111111");
		splitTest("101111 111011 111111");
		splitTest("101011 111011 111111");
		splitTest("010100 111011 111111");
		splitTest("010000 111011 111111");
		splitTest("101110 111010 111111");
		splitTest("101011 111010 111111");
		splitTest("010100 111010 111111");
		splitTest("010001 111010 111111");
		splitTest("101011 101111 111111");
		splitTest("010100 101111 111111");
		splitTest("000100 101111 111111");
		splitTest("101011 101110 111111");
		splitTest("010100 101110 111111");
		splitTest("000101 101110 111111");
		splitTest("101010 101011 111111");
		splitTest("010101 101011 111111");
		splitTest("010001 101011 111111");
		splitTest("010000 101011 111111");
		splitTest("000101 101011 111111");
		splitTest("000100 101011 111111");
		splitTest("000001 101011 111111");
		splitTest("010100 101010 111111");
		splitTest("000001 101010 111111");
		splitTest("010100 010101 111111");
		splitTest("000001 010101 111111");
		splitTest("010001 010100 111111");
		splitTest("010000 010100 111111");
		splitTest("000101 010100 111111");
		splitTest("000100 010100 111111");
		splitTest("000001 010100 111111");
		splitTest("000101 010001 111111");
		splitTest("000100 010000 111111");
		splitTest("101010 110101 111110");
		splitTest("100001 110101 111110");
		splitTest("011111 110101 111110");
		splitTest("010100 110101 111110");
		splitTest("101010 110100 111110");
		splitTest("100000 110100 111110");
		splitTest("011110 110100 111110");
		splitTest("010100 110100 111110");
		splitTest("101010 101011 111110");
		splitTest("010100 101011 111110");
		splitTest("000001 101011 111110");
		splitTest("100001 101010 111110");
		splitTest("100000 101010 111110");
		splitTest("011111 101010 111110");
		splitTest("011110 101010 111110");
		splitTest("010101 101010 111110");
		splitTest("001011 101010 111110");
		splitTest("001010 101010 111110");
		splitTest("000001 101010 111110");
		splitTest("010100 100001 111110");
		splitTest("001011 100001 111110");
		splitTest("010100 100000 111110");
		splitTest("001010 100000 111110");
		splitTest("010100 011111 111110");
		splitTest("001011 011111 111110");
		splitTest("010100 011110 111110");
		splitTest("001010 011110 111110");
		splitTest("010100 010101 111110");
		splitTest("000001 010101 111110");
		splitTest("001011 010100 111110");
		splitTest("001010 010100 111110");
		splitTest("000001 010100 111110");
		splitTest("101111 110100 111011");
		splitTest("100000 110100 111011");
		splitTest("011011 110100 111011");
		splitTest("010100 110100 111011");
		splitTest("101111 110000 111011");
		splitTest("100100 110000 111011");
		splitTest("011111 110000 111011");
		splitTest("010100 110000 111011");
		splitTest("101011 101111 111011");
		splitTest("100100 101111 111011");
		splitTest("100000 101111 111011");
		splitTest("011111 101111 111011");
		splitTest("011011 101111 111011");
		splitTest("010000 101111 111011");
		splitTest("001111 101111 111011");
		splitTest("001011 101111 111011");
		splitTest("000100 101111 111011");
		splitTest("010100 101011 111011");
		splitTest("000100 101011 111011");
		splitTest("010100 100100 111011");
		splitTest("001011 100100 111011");
		splitTest("010100 100000 111011");
		splitTest("001111 100000 111011");
		splitTest("010100 011111 111011");
		splitTest("001011 011111 111011");
		splitTest("010100 011011 111011");
		splitTest("001111 011011 111011");
		splitTest("010000 010100 111011");
		splitTest("001111 010100 111011");
		splitTest("001011 010100 111011");
		splitTest("000100 010100 111011");
		splitTest("000100 010000 111011");
		splitTest("101110 110101 111010");
		splitTest("100001 110101 111010");
		splitTest("011011 110101 111010");
		splitTest("010100 110101 111010");
		splitTest("101110 110000 111010");
		splitTest("100100 110000 111010");
		splitTest("011110 110000 111010");
		splitTest("010100 110000 111010");
		splitTest("101011 101110 111010");
		splitTest("100100 101110 111010");
		splitTest("100001 101110 111010");
		splitTest("011110 101110 111010");
		splitTest("011011 101110 111010");
		splitTest("010001 101110 111010");
		splitTest("001111 101110 111010");
		splitTest("001010 101110 111010");
		splitTest("000101 101110 111010");
		splitTest("010100 101011 111010");
		splitTest("000101 101011 111010");
		splitTest("010100 100100 111010");
		splitTest("001010 100100 111010");
		splitTest("010100 100001 111010");
		splitTest("001111 100001 111010");
		splitTest("010100 011110 111010");
		splitTest("001010 011110 111010");
		splitTest("010100 011011 111010");
		splitTest("001111 011011 111010");
		splitTest("010001 010100 111010");
		splitTest("001111 010100 111010");
		splitTest("001010 010100 111010");
		splitTest("000101 010100 111010");
		splitTest("000101 010001 111010");
		splitTest("100101 110001 110101");
		splitTest("100001 110001 110101");
		splitTest("010100 110001 110101");
		splitTest("010000 110001 110101");
		splitTest("100001 101110 110101");
		splitTest("010100 101110 110101");
		splitTest("001111 101110 110101");
		splitTest("100001 101010 110101");
		splitTest("010100 101010 110101");
		splitTest("001011 101010 110101");
		splitTest("100001 100101 110101");
		splitTest("010100 100101 110101");
		splitTest("000100 100101 110101");
		splitTest("011111 100001 110101");
		splitTest("011011 100001 110101");
		splitTest("010000 100001 110101");
		splitTest("001111 100001 110101");
		splitTest("001011 100001 110101");
		splitTest("000100 100001 110101");
		splitTest("010100 011111 110101");
		splitTest("001011 011111 110101");
		splitTest("010100 011011 110101");
		splitTest("001111 011011 110101");
		splitTest("010000 010100 110101");
		splitTest("001111 010100 110101");
		splitTest("001011 010100 110101");
		splitTest("000100 010100 110101");
		splitTest("000100 010000 110101");
		splitTest("100101 110001 110100");
		splitTest("100000 110001 110100");
		splitTest("010100 110001 110100");
		splitTest("010001 110001 110100");
		splitTest("100000 101111 110100");
		splitTest("010100 101111 110100");
		splitTest("001111 101111 110100");
		splitTest("100000 101010 110100");
		splitTest("010100 101010 110100");
		splitTest("001010 101010 110100");
		splitTest("100000 100101 110100");
		splitTest("010100 100101 110100");
		splitTest("000101 100101 110100");
		splitTest("011110 100000 110100");
		splitTest("011011 100000 110100");
		splitTest("010001 100000 110100");
		splitTest("001111 100000 110100");
		splitTest("001010 100000 110100");
		splitTest("000101 100000 110100");
		splitTest("010100 011110 110100");
		splitTest("001010 011110 110100");
		splitTest("010100 011011 110100");
		splitTest("001111 011011 110100");
		splitTest("010001 010100 110100");
		splitTest("001111 010100 110100");
		splitTest("001010 010100 110100");
		splitTest("000101 010100 110100");
		splitTest("000101 010001 110100");
		splitTest("100101 110000 110001");
		splitTest("100100 110000 110001");
		splitTest("010101 110000 110001");
		splitTest("010100 110000 110001");
		splitTest("100100 100101 110001");
		splitTest("100001 100101 110001");
		splitTest("100000 100101 110001");
		splitTest("010101 100101 110001");
		splitTest("010001 100101 110001");
		splitTest("010000 100101 110001");
		splitTest("000101 100101 110001");
		splitTest("000100 100101 110001");
		splitTest("000001 100101 110001");
		splitTest("010100 100100 110001");
		splitTest("000001 100100 110001");
		splitTest("010100 100001 110001");
		splitTest("000100 100001 110001");
		splitTest("010100 100000 110001");
		splitTest("000101 100000 110001");
		splitTest("010100 010101 110001");
		splitTest("000001 010101 110001");
		splitTest("010001 010100 110001");
		splitTest("010000 010100 110001");
		splitTest("000101 010100 110001");
		splitTest("000100 010100 110001");
		splitTest("000001 010100 110001");
		splitTest("000101 010001 110001");
		splitTest("000100 010000 110001");
		splitTest("100100 101111 110000");
		splitTest("010100 101111 110000");
		splitTest("001011 101111 110000");
		splitTest("100100 101110 110000");
		splitTest("010100 101110 110000");
		splitTest("001010 101110 110000");
		splitTest("100100 100101 110000");
		splitTest("010100 100101 110000");
		splitTest("000001 100101 110000");
		splitTest("011111 100100 110000");
		splitTest("011110 100100 110000");
		splitTest("010101 100100 110000");
		splitTest("001011 100100 110000");
		splitTest("001010 100100 110000");
		splitTest("000001 100100 110000");
		splitTest("010100 011111 110000");
		splitTest("001011 011111 110000");
		splitTest("010100 011110 110000");
		splitTest("001010 011110 110000");
		splitTest("010100 010101 110000");
		splitTest("000001 010101 110000");
		splitTest("001011 010100 110000");
		splitTest("001010 010100 110000");
		splitTest("000001 010100 110000");
		splitTest("010100 101011 101111");
		splitTest("010000 101011 101111");
		splitTest("011111 100100 101111");
		splitTest("010100 100100 101111");
		splitTest("011011 100000 101111");
		splitTest("010100 100000 101111");
		splitTest("010100 011111 101111");
		splitTest("001011 011111 101111");
		splitTest("010100 011011 101111");
		splitTest("001111 011011 101111");
		splitTest("010000 010100 101111");
		splitTest("001111 010100 101111");
		splitTest("001011 010100 101111");
		splitTest("000100 010100 101111");
		splitTest("000100 010000 101111");
		splitTest("010100 101011 101110");
		splitTest("010001 101011 101110");
		splitTest("011110 100100 101110");
		splitTest("010100 100100 101110");
		splitTest("011011 100001 101110");
		splitTest("010100 100001 101110");
		splitTest("010100 011110 101110");
		splitTest("001010 011110 101110");
		splitTest("010100 011011 101110");
		splitTest("001111 011011 101110");
		splitTest("010001 010100 101110");
		splitTest("001111 010100 101110");
		splitTest("001010 010100 101110");
		splitTest("000101 010100 101110");
		splitTest("000101 010001 101110");
		splitTest("010101 101010 101011");
		splitTest("010100 101010 101011");
		splitTest("010100 010101 101011");
		splitTest("000001 010101 101011");
		splitTest("010001 010100 101011");
		splitTest("010000 010100 101011");
		splitTest("000101 010100 101011");
		splitTest("000100 010100 101011");
		splitTest("000001 010100 101011");
		splitTest("000101 010001 101011");
		splitTest("000100 010000 101011");
		splitTest("011111 100001 101010");
		splitTest("010100 100001 101010");
		splitTest("011110 100000 101010");
		splitTest("010100 100000 101010");
		splitTest("010100 011111 101010");
		splitTest("001011 011111 101010");
		splitTest("010100 011110 101010");
		splitTest("001010 011110 101010");
		splitTest("010100 010101 101010");
		splitTest("000001 010101 101010");
		splitTest("001011 010100 101010");
		splitTest("001010 010100 101010");
		splitTest("000001 010100 101010");
		splitTest("010101 100100 100101");
		splitTest("010100 100100 100101");
		splitTest("010100 100001 100101");
		splitTest("010000 100001 100101");
		splitTest("010100 100000 100101");
		splitTest("010001 100000 100101");
		splitTest("010100 010101 100101");
		splitTest("000001 010101 100101");
		splitTest("010001 010100 100101");
		splitTest("010000 010100 100101");
		splitTest("000101 010100 100101");
		splitTest("000100 010100 100101");
		splitTest("000001 010100 100101");
		splitTest("000101 010001 100101");
		splitTest("000100 010000 100101");
		splitTest("010100 011111 100100");
		splitTest("001011 011111 100100");
		splitTest("010100 011110 100100");
		splitTest("001010 011110 100100");
		splitTest("010100 010101 100100");
		splitTest("000001 010101 100100");
		splitTest("001011 010100 100100");
		splitTest("001010 010100 100100");
		splitTest("000001 010100 100100");
		splitTest("010100 011111 100001");
		splitTest("001011 011111 100001");
		splitTest("010100 011011 100001");
		splitTest("001111 011011 100001");
		splitTest("010000 010100 100001");
		splitTest("001111 010100 100001");
		splitTest("001011 010100 100001");
		splitTest("000100 010100 100001");
		splitTest("000100 010000 100001");
		splitTest("010100 011110 100000");
		splitTest("001010 011110 100000");
		splitTest("010100 011011 100000");
		splitTest("001111 011011 100000");
		splitTest("010001 010100 100000");
		splitTest("001111 010100 100000");
		splitTest("001010 010100 100000");
		splitTest("000101 010100 100000");
		splitTest("000101 010001 100000");
		splitTest("010100 011010 011111");
		splitTest("010001 011010 011111");
		splitTest("001110 011010 011111");
		splitTest("001011 011010 011111");
		splitTest("010001 010100 011111");
		splitTest("001110 010100 011111");
		splitTest("000101 010100 011111");
		splitTest("001011 010001 011111");
		splitTest("000101 010001 011111");
		splitTest("001011 001110 011111");
		splitTest("000101 001110 011111");
		splitTest("000101 001011 011111");
		splitTest("010100 011010 011110");
		splitTest("010000 011010 011110");
		splitTest("001110 011010 011110");
		splitTest("001010 011010 011110");
		splitTest("010000 010100 011110");
		splitTest("001110 010100 011110");
		splitTest("000100 010100 011110");
		splitTest("001010 010000 011110");
		splitTest("000100 010000 011110");
		splitTest("001010 001110 011110");
		splitTest("000100 001110 011110");
		splitTest("000100 001010 011110");
		splitTest("010101 011010 011011");
		splitTest("010100 011010 011011");
		splitTest("001111 011010 011011");
		splitTest("001110 011010 011011");
		splitTest("010100 010101 011011");
		splitTest("001111 010101 011011");
		splitTest("000001 010101 011011");
		splitTest("001110 010100 011011");
		splitTest("000001 010100 011011");
		splitTest("001110 001111 011011");
		splitTest("000001 001111 011011");
		splitTest("000001 001110 011011");
		splitTest("010100 010101 011010");
		splitTest("001110 010101 011010");
		splitTest("000001 010101 011010");
		splitTest("010001 010100 011010");
		splitTest("010000 010100 011010");
		splitTest("001111 010100 011010");
		splitTest("001011 010100 011010");
		splitTest("001010 010100 011010");
		splitTest("000101 010100 011010");
		splitTest("000100 010100 011010");
		splitTest("000001 010100 011010");
		splitTest("001110 010001 011010");
		splitTest("000101 010001 011010");
		splitTest("001110 010000 011010");
		splitTest("000100 010000 011010");
		splitTest("001110 001111 011010");
		splitTest("000001 001111 011010");
		splitTest("001011 001110 011010");
		splitTest("001010 001110 011010");
		splitTest("000101 001110 011010");
		splitTest("000100 001110 011010");
		splitTest("000001 001110 011010");
		splitTest("000101 001011 011010");
		splitTest("000100 001010 011010");
		splitTest("001111 010100 010101");
		splitTest("001110 010100 010101");
		splitTest("001110 001111 010101");
		splitTest("000001 001111 010101");
		splitTest("000001 001110 010101");
		splitTest("001110 010001 010100");
		splitTest("001011 010001 010100");
		splitTest("001110 010000 010100");
		splitTest("001010 010000 010100");
		splitTest("001110 001111 010100");
		splitTest("000001 001111 010100");
		splitTest("001011 001110 010100");
		splitTest("001010 001110 010100");
		splitTest("000101 001110 010100");
		splitTest("000100 001110 010100");
		splitTest("000001 001110 010100");
		splitTest("000101 001011 010100");
		splitTest("000100 001010 010100");
		splitTest("001011 001110 010001");
		splitTest("000101 001110 010001");
		splitTest("000101 001011 010001");
		splitTest("001010 001110 010000");
		splitTest("000100 001110 010000");
		splitTest("000100 001010 010000");
		// make(d);
		// splitTest("110100");
	}

	public void make(int k) {
		if (k == 0) {
			calc(tmp);
		} else {
			for (int i = 0; i <= maxIn; ++i) {
				tmp[k - 1] = i;
				make(k - 1);
			}
		}
	}

	public void calc(int[] diff) {
		int m = 1 << d, v = 0, tmp = 0;
		int[] a = new int[m];
		for (int i = 0; i < m; ++i) {
			v = i;
			tmp = 0;
			for (int j = 0; j < d; ++j) {
				if ((v & 1) == 1)
					tmp ^= diff[j];
				v = v >> 1;
			}
			a[i] = tmp & maxIn;
		}
		int[] result = new int[maxOut + 1];
		for (int i = 0; i <= maxIn; ++i) {
			int t = 0;
			for (int j = 0; j < m; ++j)
				t ^= fun.calc(i ^ a[j]);
			// for (int j = 0; j < m; ++j)
			// out.print((i ^ a[j]) + " - " + fun.calc(i ^ a[j]) + " ");
			// out.println(" : " + i + " " + t);
			++result[t];
		}
		for (int i = 0; i < d; ++i)
			out.print(toHex(diff[i]) + " ");
		out.print(":");
		for (int i = 0; i <= maxOut; ++i)
			out.print(toString(result[i]) + " ");
		out.println();
	}

	private void splitTest(String s) {
		String[] in = s.split(" ");
		for (int i = 0; i < d; ++i)
			tmp[i] = Integer.valueOf(in[i], 2);
		calc(tmp);
	}

	private String toHex(int n) {
		String ret = Integer.toHexString(n);
		if (ret.length() == 1)
			ret = "0" + ret;
		return ret;
	}

	private String toString(int n) {
		String ret = Integer.toString(n);
		if (ret.length() == 1)
			ret = " " + ret;
		return ret;
	}

	public static void main(String[] args) {
		try {
			FileOutputStream out = new FileOutputStream("d://123.txt");
			new Generate(new bfDES(1), 3, new PrintStream(out));
			out.flush();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
